#ifndef _USR_XDMA_H_
#define _USR_XDMA_H_

#include <stdint.h>
#include "pthread_own.h"
#include "interface_emum.h"

#define DATA_INFORMER_MAX_NUM 16
#define C2H_CHANNEL_MAX_NUM 4
#define H2C_CHANNEL_MAX_NUM 4

#define H2C_CHANNEL_IDENTIFIER_OFFSET  0x0000
#define C2H_CHANNEL_IDENTIFIER_OFFSET  0x1000
#define IRQ_BLOCK_IDENTIFIER_OFFSET    0x2000
#define CONFIG_BLOCK_IDENTIFIER_OFFSET 0x3000
#define H2C_SGDMA_IDENTIFIER_OFFSET    0x4000
#define SGDMA_COMMON_IDENTIFIER_OFFSET 0x6000

#if 1
#define C2H_CHANNEL_PATH_BASE           "/dev/xdma0_c2h_"
#define H2C_CHANNEL_PATH_BASE           "/dev/xdma0_h2c_"
#define DATA_INFORMER_PATH_BASE         "/dev/xdma0_events_"
#define USR_CONFIG_BAR_PATH             "/dev/xdma0_user"
#define XDMA_CONFIG_BAR_PATH            "/dev/xdma0_control"
#define LOW_SPEED_PORT_R_INFORMER_PATH  "/dev/xdma0_events_1"
#else
#define C2H_CHANNEL_PATH_BASE           "/dev/ucas_xdma00_c2h_"
#define H2C_CHANNEL_PATH_BASE           "/dev/ucas_xdma00_h2c_"
#define DATA_INFORMER_PATH_BASE         "/dev/ucas_xdma00_usr_irq"
#define USR_CONFIG_BAR_PATH             "/dev/ucas_xdma00_usr_reg_rw"
#define XDMA_CONFIG_BAR_PATH            "/dev/ucas_xdma00_ctl_reg_rw"
#define LOW_SPEED_PORT_R_INFORMER_PATH  "/dev/ucas_xdma00_usr_irq1"
#endif

#define FPGA_CTR_REG                    0x00008000
#define CLEAR_IRQ_CMD                   0x00000001
#define USR_BE_READY_CMD                0x00000002

#define FPGA_RING_BUFF_CONFIG_OFFSET    0x00000800

#define FPGA_IRQ_CTL_REG                0x0000000c
#define FPGA_IRQ_ENBALE                 0x00000004

#define FPGA_SIDE_DMA_WRITE_ENABLE_REG  0x00000004
#define FPGA_SIDE_DMA_WRITE_ENABLE      0x00000002

#define FPGA_sdma_RESET                 0X00000001

#define BLOCK_ALIGN 4096
#define ADDRESS_ALIGN(address,align)  (void *)(((uint64_t)address + align - 1) & (~(align - 1)))

typedef struct
{
    unsigned int block_type;
    unsigned int block_size;
    unsigned char block[DEFAULT_MSG_SIZE];
} data_block_str;

typedef struct
{
    unsigned int block_type;
    unsigned int block_size;
    unsigned int block_number;
} mem_block_str;

typedef struct
{
    long int msg_type;
    mem_block_str block;
} msg_st;

typedef struct
{
    char        *c2h_channel_path[C2H_CHANNEL_MAX_NUM];
    int         c2h_channel_fd[C2H_CHANNEL_MAX_NUM];
    int         c2h_channel_count;
    int         c2h_share_memory_id[C2H_CHANNEL_MAX_NUM];
    int         c2h_msg_queue_id[C2H_CHANNEL_MAX_NUM];
    msg_st      c2h_msg_st[C2H_CHANNEL_MAX_NUM];
    int         c2h_thread_running;     //0 for running,1 for stop
    pthread_t   c2h_thread[C2H_CHANNEL_MAX_NUM];             //c2h_thread id
    char        *c2h_block_buff[C2H_CHANNEL_MAX_NUM];
    char        *c2h_block_buff_aligned[C2H_CHANNEL_MAX_NUM];//the address must be 4096 aliged
    int         c2h_data_informer_fd[C2H_CHANNEL_MAX_NUM];
/////////////////////////////////////////////////////
    char        *h2c_channel_path[H2C_CHANNEL_MAX_NUM];
    int         h2c_channel_fd[H2C_CHANNEL_MAX_NUM];
    int         h2c_channel_count;
    int         h2c_share_memory_id[H2C_CHANNEL_MAX_NUM];
    int         h2c_msg_queue_id[H2C_CHANNEL_MAX_NUM];
    msg_st      h2c_msg_st[H2C_CHANNEL_MAX_NUM];
    int         h2c_thread_running;     //0 for running,1 for stop
    pthread_t   h2c_thread[H2C_CHANNEL_MAX_NUM];             //h2c_thread id
    char        *h2c_block_buff[C2H_CHANNEL_MAX_NUM];
    char        *h2c_block_buff_aligned[C2H_CHANNEL_MAX_NUM];//the address must be 4096 aliged
    int         h2c_data_informer_fd[C2H_CHANNEL_MAX_NUM];
/////////////////////////////////////////////////////
    char        *data_informer_path[DATA_INFORMER_MAX_NUM];
    int         data_informer_fd[DATA_INFORMER_MAX_NUM];
/////////////////////////////////////////////////////
    char        *usr_config_bar_map_address;
    int         usr_config_bar_fd;
    char        *xdma_config_bar_map_address;
    int         xdma_config_bar_fd;
/////////////////////////////////////////////////////
    int         fpga_side_ring_buffer_block_num;
    uint32_t    fpga_side_ring_buffer_block_size;
    int         user_side_ring_buffer_block_num;
    uint32_t    user_side_ring_buffer_block_size;
/////////////////////////////////////////////////////
    uint64_t    c2h_data_len[C2H_CHANNEL_MAX_NUM];       //srio data recieved
    float       c2h_data_speed[C2H_CHANNEL_MAX_NUM];     //srio data recieved speed MB/s
    uint64_t    deliver_data_len[C2H_CHANNEL_MAX_NUM];   //data deliver to algo
    float       deliver_data_speed[C2H_CHANNEL_MAX_NUM]; //data deliver speed MB/s
    uint64_t    h2c_data_len[H2C_CHANNEL_MAX_NUM];       //srio data sended
    float       h2c_data_speed[H2C_CHANNEL_MAX_NUM];     //srio data sended speed MB/s
    uint64_t    rcv_data_len[H2C_CHANNEL_MAX_NUM];       //data rcv from algo
    float       rcv_data_speed[H2C_CHANNEL_MAX_NUM];     //data rcv from algo speed MB/s

    int         monitor_period;             //monitor period
    int         monitor_thread_running;     //0 for running,1 for stop
    pthread_t   monitor_thread;             //monitor_thread id
    int         num_of_user_data_channel;   //the number of user data channels
    int         direction;                  //1->read 2->write 3->read/write
    int         deliver_data;               //1->deliver_data 0->do not deliver
/////////////////////////////////////////////////////
} xdma_usr_dev;
#define C2H_READ_DATA           0x00000001
#define H2C_WRITE_DATA          0x00000002
#define C2H_H2C_READ_WRITE_DATA 0x00000003

#define C2H_MSG_TYPE            0x00000001
#define H2C_MSG_TYPE            0x00000002

extern int init_get_data_informer(const char *path);
extern int xdma_dev_init(xdma_usr_dev *dev);
extern int xdma_dev_deinit(xdma_usr_dev *dev);
extern int dump_xdma_dev(xdma_usr_dev *dev);
extern int is_data_ready(int fd);
extern int write_bar(char *map_base, off_t target, uint32_t value);
extern uint32_t read_bar(char *map_base, off_t target);
#endif
